#ifndef ATOMIC_H_
#define ATOMIC_H_

#include <cstdint>

#include "netlib/base/noncopyable.h"

namespace netlib {
namespace detail {

template <typename T> class AtomicIntegerT : NonCopyable {
public:
	AtomicIntegerT() : value_(0) {}

	// uncomment if you need copying and assignment
	//
	// AtomicIntegerT(const AtomicIntegerT& that)
	//   : value_(that.get())
	// {}
	//
	// AtomicIntegerT& operator=(const AtomicIntegerT& that)
	// {
	//   getAndSet(that.get());
	//   return *this;
	// }

	T Get() {
		// in gcc >= 4.7: __atomic_load_n(&value_,
		// __ATOMIC_SEQ_CST)
		return __sync_val_compare_and_swap(&value_, 0, 0);
	}

	T GetAndAdd(T x) {
		// in gcc >= 4.7: __atomic_fetch_add(&value_, x,
		// __ATOMIC_SEQ_CST)
		return __sync_fetch_and_add(&value_, x);
	}

	T AddAndGet(T x) { return GetAndAdd(x) + x; }

	T IncrementAndGet() { return AddAndGet(1); }

	T DecrementAndGet() { return AddAndGet(-1); }

	void Add(T x) { GetAndAdd(x); }

	void Increment() { IncrementAndGet(); }

	void Decrement() { DecrementAndGet(); }

	T GetAndSet(T newValue) {
		// in gcc >= 4.7: __atomic_exchange_n(&value_, newValue,
		// __ATOMIC_SEQ_CST)
		return __sync_lock_test_and_set(&value_, newValue);
	}

private:
	volatile T value_;
};
} // namespace detail

using AtomicInt32 = detail::AtomicIntegerT<int32_t>;
using AtomicInt64 = detail::AtomicIntegerT<int64_t>;

} // namespace netlib

#endif // ATOMIC_H_